/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-12-05     LOJAM       the first version
 */



#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "blehr_sens.h"
#include "ble_smarthome.h"
#include "rtdbg.h"

static const char *manuf_name = "光明谷";  //Sunshine Silicon";  //可以中文得长度长了,上报不了数据
static const char *model_num = "SS-SMRT01";
uint16_t smrthm_ctrl_handle;

static gatt_svr_event_handle_t gatt_srv_event_handle = NULL;

void my_print_r(const void *buf, uint16_t cnt);

static int gatt_svr_chr_access_smrthm(uint16_t conn_handle, uint16_t attr_handle,
                               struct ble_gatt_access_ctxt *ctxt, void *arg);

static int gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
                                struct ble_gatt_access_ctxt *ctxt, void *arg);

static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
    {
        /* Service: Smarthome Control */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(GATT_SMRTHM_UUID),
        .characteristics = (struct ble_gatt_chr_def[]) { {
            /* Characteristic: Smarthome Status report */
            .uuid = BLE_UUID16_DECLARE(GATT_SMRTHM_STATUS_UUID),
            .access_cb = gatt_svr_chr_access_smrthm,
            .val_handle = &smrthm_ctrl_handle,
            .flags = BLE_GATT_CHR_F_NOTIFY,
        }, {
            /* Characteristic: Smarthome Control eLock Light  */
            .uuid = BLE_UUID16_DECLARE(GATT_SMRTHM_CTRL_UUID),
            .access_cb = gatt_svr_chr_access_smrthm,
            .flags = BLE_GATT_CHR_F_READ|BLE_GATT_CHR_F_WRITE,
        }, {
            0, /* No more characteristics in this service */
        }, }
    },

    {
        /* Service: Device Information */
        .type = BLE_GATT_SVC_TYPE_PRIMARY,
        .uuid = BLE_UUID16_DECLARE(GATT_DEVICE_INFO_UUID),
        .characteristics = (struct ble_gatt_chr_def[]) { {
            /* Characteristic: * Manufacturer name */
            .uuid = BLE_UUID16_DECLARE(GATT_MANUFACTURER_NAME_UUID),
            .access_cb = gatt_svr_chr_access_device_info,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            /* Characteristic: Model number string */
            .uuid = BLE_UUID16_DECLARE(GATT_MODEL_NUMBER_UUID),
            .access_cb = gatt_svr_chr_access_device_info,
            .flags = BLE_GATT_CHR_F_READ,
        }, {
            0, /* No more characteristics in this service */
        }, }
    },

        {
            0, /* No more services */
        },
};


/*
 * Smarthome control Handle
 */
static int gatt_svr_chr_access_smrthm(uint16_t conn_handle, uint16_t attr_handle,
                               struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    /* Sensor location, set to "Chest" */
    static uint8_t gatt_recvBuf[20];
    uint8_t status_buf[2];
    uint8_t smrthm_ctrl_val = 0x01;
    uint8_t recvLen;
    uint16_t uuid;
    int rc = 0;

    uuid = ble_uuid_u16(ctxt->chr->uuid);

    if (uuid == GATT_SMRTHM_CTRL_UUID) {
         /**
           * ctxt->op
           * Indicates the gatt operation being performed.  This is equal to one of
           * the following values:
           *     o  BLE_GATT_ACCESS_OP_READ_CHR
           *     o  BLE_GATT_ACCESS_OP_WRITE_CHR
           *     o  BLE_GATT_ACCESS_OP_READ_DSC
           *     o  BLE_GATT_ACCESS_OP_WRITE_DSC
           */
        if(BLE_GATT_ACCESS_OP_READ_CHR == ctxt->op)
        {
//            rc = os_mbuf_append(ctxt->om, &smrthm_ctrl_val, sizeof(smrthm_ctrl_val));
            if(gatt_srv_event_handle)
            {
                gatt_srv_event_handle(status_read_event_id, (void *)status_buf);
                rc = os_mbuf_append(ctxt->om, status_buf, sizeof(status_buf));
                return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
            }

            return BLE_ATT_ERR_INSUFFICIENT_RES;
        }
        else if(BLE_GATT_ACCESS_OP_WRITE_CHR == ctxt->op)
        {
//            rc = os_mbuf_append(recvBuf, (void *)ctxt->om->om_data, ctxt->om->om_len);
            memset (gatt_recvBuf, 0, sizeof(gatt_recvBuf));
            recvLen = ctxt->om->om_len;
            memcpy (gatt_recvBuf, (void *)ctxt->om->om_data, recvLen); //sizeof(*ctxt->om->om_data)
            if(gatt_srv_event_handle)
            {
                gatt_srv_event_handle(ctrl_write_event_id, (void *)gatt_recvBuf);
            }
//            LOG_I("Recv dat:");
            rt_kprintf("Recv %d bytes data:\n", recvLen);
            my_print_r(gatt_recvBuf, recvLen);
            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
        }
    }
//    assert(0);
    return BLE_ATT_ERR_UNLIKELY;
}

/*
 * Device info handle
 */

static int gatt_svr_chr_access_device_info(uint16_t conn_handle, uint16_t attr_handle,
                                struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    uint16_t uuid;
    int rc;

    uuid = ble_uuid_u16(ctxt->chr->uuid);

    if (uuid == GATT_MODEL_NUMBER_UUID) {
        rc = os_mbuf_append(ctxt->om, model_num, strlen(model_num));
        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
    }

    if (uuid == GATT_MANUFACTURER_NAME_UUID) {
        rc = os_mbuf_append(ctxt->om, manuf_name, strlen(manuf_name));
        return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
    }

    assert(0);
    return BLE_ATT_ERR_UNLIKELY;
}

void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
{
    char buf[BLE_UUID_STR_LEN];

    switch (ctxt->op) {
    case BLE_GATT_REGISTER_OP_SVC:
        MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
                    ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
                    ctxt->svc.handle);
        break;

    case BLE_GATT_REGISTER_OP_CHR:
        MODLOG_DFLT(DEBUG, "registering characteristic %s with "
                           "def_handle=%d val_handle=%d\n",
                    ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
                    ctxt->chr.def_handle,
                    ctxt->chr.val_handle);
        break;

    case BLE_GATT_REGISTER_OP_DSC:
        MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
                    ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
                    ctxt->dsc.handle);
        break;

    default:
        assert(0);
        break;
    }
}

int gatt_svr_init(void)
{
    int rc;

    rc = ble_gatts_count_cfg(gatt_svr_svcs);
    if (rc != 0) {
        return rc;
    }

    rc = ble_gatts_add_svcs(gatt_svr_svcs);
    if (rc != 0) {
        return rc;
    }

    return 0;
}

void reg_gatt_event_handle(gatt_svr_event_handle_t event_handle)
{
    if(event_handle)
    {
        gatt_srv_event_handle = event_handle;
    }
}
